/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.pa165.sme.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;

import cz.muni.fi.pa165.sme.dao.api.SportActivityDao;
import cz.muni.fi.pa165.sme.dao.entity.SportActivity;
import cz.muni.fi.pa165.sme.dao.exception.DataStorageOperationException;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import static cz.muni.fi.pa165.sme.common.EntityValidator.validateDeleteEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateEntityManager;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateGetEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateNewEntity;
import static cz.muni.fi.pa165.sme.common.EntityValidator.validateUpdatedEntity;

/**
 *
 * @author Martin Nov?k
 */
@Repository
public class SportActivityDaoImpl implements SportActivityDao {
    
    @PersistenceContext
    private EntityManager entityManager;

    public void setEntityManager(EntityManager entityManager) {
            this.entityManager = entityManager;
    }
    
    @Override
    @Cascade(CascadeType.PERSIST)
    @Transactional
    public void createSportActivity(final SportActivity sportActivity) {
        validateEntityManager(entityManager);
        validateNewEntity(sportActivity);

        try{
            entityManager.persist(sportActivity);
        }catch (PersistenceException e){
            throw new DataStorageOperationException("An error has occurred while inserting a new sport activity " +
                            "object to the database",e);
        }
        entityManager.flush();
    }

    @Override
    @Transactional
    public void deleteSportActivity(final SportActivity sportActivity) {
        validateEntityManager(entityManager);
        validateDeleteEntity(sportActivity);

        try {
            entityManager.remove(entityManager.find(SportActivity.class, sportActivity.getId()));
        } catch (PersistenceException e){
            throw new DataStorageOperationException("An error has occurred while deleting Sport activity from " +
                    "the database",e);
        } catch (IllegalArgumentException e){
            throw new DataStorageOperationException("Sport activity: " + sportActivity + " does not exist " +
                    "in the database, or the argument is invalid",e);
        }
    }

    @Override
    @Cascade(CascadeType.SAVE_UPDATE)
    @Transactional
    public void updateSportActivity(final SportActivity sportActivity) {
        validateEntityManager(entityManager);
        validateUpdatedEntity(sportActivity);

        try{
            final SportActivity oldRecord = entityManager.find(SportActivity.class, sportActivity.getId());
            if(oldRecord == null) {
                throw new IllegalArgumentException("Entity cannot be updated if it does not exist.");
            }

            entityManager.merge(sportActivity);
        } catch (PersistenceException e){
            throw new DataStorageOperationException("An error has occurred while updating sport activity in database",e);
        } catch (IllegalArgumentException e){
            throw new DataStorageOperationException("Sport activity: " + sportActivity + "does not exist in the database," +
                    " or the argument is wrong",e);
        }
    }

    @Override
    public SportActivity findSportActivityById(Long id) {
        validateGetEntity(id);
        validateEntityManager(entityManager);

        try {
            return entityManager.find(SportActivity.class, id);
        } catch (PersistenceException ex) {
            throw new DataStorageOperationException("An error has occured when looking for a sport activity in database by id "+id, ex);
        }
    }

    @Override
    public List<SportActivity> findSportActivityByTitle(String title) {
        if(title == null) {
            throw new IllegalArgumentException("Title to be looked up cannot be null");
        }

        validateEntityManager(entityManager);

        try{
            TypedQuery<SportActivity> selectByTitle = entityManager.createNamedQuery(SportActivity.SELECT_BY_TITLE, SportActivity.class);
            selectByTitle.setParameter("title", title);
            return selectByTitle.getResultList();
        } catch (PersistenceException ex) {
            throw new DataStorageOperationException("An error has occured when looking for a sport activity in database by title "+title, ex);
        }
    }

    @Override
    public List<SportActivity> findAllSportActivities() {
        validateEntityManager(entityManager);

        try{
            TypedQuery<SportActivity> selectAll = entityManager.createNamedQuery(SportActivity.SELECT_ALL, SportActivity.class);
            return selectAll.getResultList();
        } catch (PersistenceException ex) {
            throw new DataStorageOperationException("An error has occurred when looking for all sport activities in database.", ex);
        }
    }

}
